/**
 * Archivo: Principal.java
 *
 * @author Daniel Bruzual
 * @author Manuel Gómez
 * @author Marilyn Nowacka
 * @author Sabrina Fernández
 */

import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.io.*;
import nanoxml.XMLElement;
import nanoxml.XMLParseException;

/**
 * Clase que controla la sincronización de eventos
 */
class Sincronizacion {
	String proc;
	boolean estado = false;
   
	/**
	 * Toma un string que pasa el hilo productor
     */
	synchronized String get () {
		if (!estado)
			try {
				wait();
			} catch (InterruptedException e) {
				System.out.println("Error\n");
			}
		System.out.println("Consume: " + proc);
		estado = false;
		notify();
		return proc;
   }

	/**
	 * Pasa un string al hilo consumidor
	 */
	synchronized void put (String proc) {
		if (estado)
			try {
				wait();
			} catch (InterruptedException e) {
				System.out.println("Error\n");
			}
		this.proc = proc;
		estado = true;
		System.out.println("Produce: " + proc);
		notify();
   }
}

/**
 * Clase que se encarga de leer el archivo y enviar los procesos al hilo principal.
 */
class Lector_Productor implements Runnable {
	Sincronizacion s;
	Controlador c;

	Lector_Productor(Sincronizacion s, Controlador c) {
		this.s = s;
		this.c = c;
		new Thread(this,"Productor").start();
	}

	public void run() {
		int i = 0, num_proc = c.procesos.size(), num_inst = c.instrucciones.size(), num_hits, num_miss, porc_hits, porc_miss;
		String clave = null;	
		s.put(String.valueOf(c.tam_ram));
		s.put(String.valueOf(num_proc));
		Iterator<String> iterador = c.procesos.keySet().iterator();
		
		// Se le pasan los procesos con sus colores
		while ( (i < 2) && (iterador.hasNext()) ){
			clave = iterador.next();
			s.put( c.procesos.get(clave).getNombre() );
			s.put( String.valueOf(c.procesos.get(clave).getColor()) );
			i++;
		}
		i = 0;
		// Se pasan las instrucciones
		while (i < num_inst) {
			s.put( String.valueOf(c.instrucciones.get(i).getTipo()));
			s.put( String.valueOf(c.instrucciones.get(i).getDir_mem()));
			s.put( String.valueOf(c.instrucciones.get(i).getDelay()));
			s.put( String.valueOf(c.instrucciones.get(i).getEjecutor().getNombre() ) );
			s.put( String.valueOf(c.instrucciones.get(i).getEjecutor().getColor() ) );
			// Agregar mas informacion importante
			i++;
		}

		// Se debe haber hecho todo lo que ejecutaba las instrucciones
 
		// Se pasan las estadisticas	
		num_hits = c.manejadorIns.getHits();
		num_miss = c.manejadorIns.getMiss();
		s.put(String.valueOf(num_hits));
		s.put(String.valueOf(num_miss));
	}
}

class Interfaz_Consumidor implements Runnable {
	Sincronizacion s;
	Controlador c;

	Interfaz_Consumidor(Sincronizacion s, Controlador c) {
		this.s = s;
		this.c = c;
		new Thread(this,"Consumidor").start();
	}

	public void run() {
		while(true) {
			s.get();
		}
	}
}

public class Principal {

    public static void main(String args[]) {
		String filename = null;
		Parser parser = new Parser();
		BufferedReader entrada;

		Controlador control = null;
		try {
			filename = args[0];
			if (parser.parseArchivo(filename) == -1) {
				System.exit(0);
			} else {
				System.out.println("Archivo: " + filename);
				control = new Controlador(parser.getProcesos(), parser.getInstrucciones(), parser.getTam_ram());
				Sincronizacion s = new Sincronizacion();
				new Lector_Productor(s,control);
				new Interfaz_Consumidor(s,control);
			}
		} catch (IndexOutOfBoundsException e) {
			System.out.println("Error\n");
			System.out.println(0);
		}
		
        
		/*EventQueue.invokeLater(new Runnable() {
            public void run() {
                new Simulador_MM().setVisible(true);
            }
        });*/
    }
	
}

